/*
*  This file is part of mangusta
*
*  mangusta is free software; you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation; either version 2 of the License, or
*  (at your option) any later version.
*
*  mangusta is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with mangusta; if not, write to the Free Software
*  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  US
*
*  Author: <antonino.calderone@ericsson.com>, <acaldmail@gmail.com>
*
*/


/* -------------------------------------------------------------------------- */

#include "nu_rt_prog_ctx.h"
#include "nu_stmt_while.h"
#include "nu_stmt_empty.h"
#include "nu_error_codes.h"


/* -------------------------------------------------------------------------- */

namespace nu
{


// -------------------------------------------------------------------------

void stmt_while_t::build_ctx(prog_ctx_t & ctx)
{
   syntax_error_if(ctx.compiletime_pc.get_stmt_pos() > 0,
                   "while must be first line statement");

   ctx.parsing_scope.push("while");
   ctx.while_metadata.compile_begin(ctx.compiletime_pc);
}


// -------------------------------------------------------------------------

stmt_while_t::stmt_while_t(
   prog_ctx_t & ctx,
   expr_any_t::handle_t condition)
   :
   stmt_t(ctx),
   _condition(condition)
{
   build_ctx(ctx);
}


// -------------------------------------------------------------------------

stmt_while_t::~stmt_while_t()
{
}


// -------------------------------------------------------------------------

stmt_t::stmt_cl_t stmt_while_t::get_cl() const throw()
{
   return stmt_cl_t::WHILE_BEGIN;
}


// -------------------------------------------------------------------------

void stmt_while_t::run(rt_prog_ctx_t& ctx)
{

   //  while (<condition>) {
   //   ...
   //  }

   auto & wctxs = ctx.while_metadata;
   auto handle = wctxs.begin_find(ctx.runtime_pc);

   rt_error_code_t::get_instance().throw_if(
      !handle,
      ctx.runtime_pc.get_line(),
      rt_error_code_t::E_INTERNAL,
      "while");

   if (!static_cast<bool>(_condition->eval(ctx)))
   {
      handle->flag[instrblock_t::EXIT] = true;
      ctx.go_to(handle->pc_end_stmt);
   }

   else
   {
      handle->flag[instrblock_t::EXIT] = false;
      ctx.go_to_next();
   }

   if (_break_while_loop)
   {
      ctx.flag[rt_prog_ctx_t::FLG_END_REQUEST] = true;
      _break_while_loop = false;
   }
}


// -------------------------------------------------------------------------

bool stmt_while_t::notify(const event_t& ev)
{
   _break_while_loop = ev == event_t::BREAK;
   return _break_while_loop;
}


// -------------------------------------------------------------------------

}

/* -------------------------------------------------------------------------- */

